from fastapi import APIRouter, Depends, HTTPException, Query, Body
from sqlalchemy.orm import Session
from ..database import get_db
from ..models.prompt import Prompt
from ..models.model import ModelConfig
from ..auth.jwt_handler import get_current_user
from ..models.user import User
from pydantic import BaseModel
from typing import Optional, List, Dict, Any
import uuid
import datetime
from datetime import timezone  # 导入timezone以便处理时区信息
import os

router = APIRouter(
    prefix='/prompts',  # 移除/api
    tags=['prompts'],
)

# 定义请求模型
class PromptCreate(BaseModel):
    title: str
    content: str
    description: Optional[str] = None
    version: str  # 修改为str类型，支持语义化版本号
    tags: Optional[str] = None
    model_id: Optional[int] = None
    cover_img: Optional[str] = None

# 模型配置响应模型
class ModelConfigResponse(BaseModel):
    id: int
    channel: Optional[str] = None
    channel_id: Optional[int] = None
    model: str
    temperature: Optional[float] = 1.0
    max_tokens: Optional[int] = 2048
    top_p: Optional[float] = 1.0
    presence_penalty: Optional[float] = 0.0
    frequency_penalty: Optional[float] = 0.0
    n: Optional[int] = 1
    stop: Optional[List[str]] = None
    logit_bias: Optional[Dict[str, Any]] = None
    stream: Optional[bool] = False
    response_format: Optional[str] = None
    endpoint_url: Optional[str] = None
    file_path: Optional[str] = None
    api_key: Optional[str] = None
    created_at: Optional[str] = None
    updated_at: Optional[str] = None

    class Config:
        orm_mode = True

# 定义响应模型
class PromptResponse(BaseModel):
    id: str
    title: str
    content: str
    description: Optional[str] = None
    user_id: str
    is_public: bool
    version: str  # 修改为字符串类型，因为数据库中存储的是'1.0.1'这样的版本号
    tags: Optional[str] = None
    model_id: Optional[int] = None
    cover_img: Optional[str] = None
    created_at: str
    updated_at: str
    model: Optional[ModelConfigResponse] = None  # 添加模型信息

    # 配置Pydantic模型从SQLAlchemy模型实例创建
    class Config:
        orm_mode = True
        # 自定义JSON编码器以处理UUID和datetime对象
        json_encoders = {
            uuid.UUID: lambda v: str(v),
            datetime.datetime: lambda v: v.isoformat()
        }

class UpdatePromptResponse(BaseModel):
    success: bool
    code: int
    message: str
    model_id: Optional[int] = None
    tags: Optional[str] = None
    title: Optional[str] = None

# 分页查询响应模型
class PaginatedPromptResponse(BaseModel):
    items: List[PromptResponse]
    total: int
    page: int
    page_size: int
    total_pages: int

# 校验函数
def validate_prompt_data(prompt_data: dict, model_data: dict = None):
    """校验提示词和模型数据"""
    errors = []
    
    # 提示词标题校验
    if not prompt_data.get('title', '').strip():
        errors.append("提示词标题不能为空")
    elif len(prompt_data.get('title', '').strip()) > 100:
        errors.append("提示词标题长度不能超过100个字符")
    
    # 提示词内容校验
    if not prompt_data.get('content', '').strip():
        errors.append("提示词内容不能为空")
    elif len(prompt_data.get('content', '').strip()) > 10000:
        errors.append("提示词内容长度不能超过10000个字符")
    
    # 版本号校验
    if not prompt_data.get('version', '').strip():
        errors.append("版本号不能为空")
    
    # 模型配置校验
    if model_data:
        # 渠道名称必填
        if not model_data.get('channel', '').strip():
            errors.append("渠道名称不能为空")
        
        # 模型名称必填
        if not model_data.get('model', '').strip():
            errors.append("模型名称不能为空")
        
        # temperature [0,2]
        temperature = model_data.get('temperature', 1.0)
        if not isinstance(temperature, (int, float)) or temperature < 0 or temperature > 2:
            errors.append("temperature 取值范围应在 [0, 2]")
        
        # top_p [0,2]
        top_p = model_data.get('top_p', 1.0)
        if not isinstance(top_p, (int, float)) or top_p < 0 or top_p > 2:
            errors.append("top_p 取值范围应在 [0, 2]")
        
        # max_tokens [10,30000]
        max_tokens = model_data.get('max_tokens', 2048)
        if not isinstance(max_tokens, int) or max_tokens < 10 or max_tokens > 30000:
            errors.append("max_tokens 取值范围应在 [10, 30000]")
        
        # presence_penalty [-2,2]
        presence_penalty = model_data.get('presence_penalty', 0.0)
        if not isinstance(presence_penalty, (int, float)) or presence_penalty < -2 or presence_penalty > 2:
            errors.append("presence_penalty 取值范围应在 [-2.0, 2.0]")
        
        # frequency_penalty [-2,2]
        frequency_penalty = model_data.get('frequency_penalty', 0.0)
        if not isinstance(frequency_penalty, (int, float)) or frequency_penalty < -2 or frequency_penalty > 2:
            errors.append("frequency_penalty 取值范围应在 [-2.0, 2.0]")
    
    return errors

# 分页查询提示词接口
@router.get('/queryPrompts', response_model=PaginatedPromptResponse)
def get_prompts_paginated(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
    tag: Optional[str] = Query(None, description="标签过滤"),
    title: Optional[str] = Query(None, description="提示词标题过滤"),
    version: Optional[str] = Query(None, description="提示词版本过滤"),
    page: int = Query(1, ge=1, description="当前页码，默认为1"),
    page_size: int = Query(10, ge=1, le=100, description="每页数据量，默认为10，最大100")
):
    """
    分页查询提示词接口
    查询条件：标签、提示词标题、提示词版本
    分页条件：当前页、每页数据量
    """
    query = db.query(Prompt).filter(Prompt.user_id == current_user.id)

    # 应用过滤条件
    if tag:
        query = query.filter(Prompt.tags.like(f'%{tag}%'))
    
    if title:
        query = query.filter(Prompt.title.like(f'%{title}%'))
    
    if version:
        query = query.filter(Prompt.version == version)

    # 计算总数
    total = query.count()
    
    # 分页查询
    offset = (page - 1) * page_size
    prompts = query.order_by(Prompt.created_at.desc()).offset(offset).limit(page_size).all()
    
    # 手动转换每个提示对象，包含模型信息
    result = []
    for prompt in prompts:
        # 获取模型信息
        model_info = None
        if prompt.model_id:
            model = db.query(ModelConfig).filter(ModelConfig.id == prompt.model_id).first()
            if model:
                model_info = {
                    "id": model.id,
                    "channel": model.channel,
                    "channel_id": model.channel_id,
                    "model": model.model,
                    "temperature": model.temperature,
                    "max_tokens": model.max_tokens,
                    "top_p": model.top_p,
                    "presence_penalty": model.presence_penalty,
                    "frequency_penalty": model.frequency_penalty,
                    "n": model.n,
                    "stop": model.stop,
                    "logit_bias": model.logit_bias,
                    "stream": model.stream,
                    "response_format": model.response_format,
                    "endpoint_url": model.endpoint_url,
                    "file_path": model.file_path,
                    "api_key": model.api_key,
                    "created_at": model.created_at.isoformat() if model.created_at else None,
                    "updated_at": None  # ModelConfig 没有 updated_at 字段
                }
        
        prompt_dict = {
            "id": str(prompt.id),
            "title": prompt.title,
            "content": prompt.content,
            "description": prompt.description,
            "user_id": str(prompt.user_id),
            "is_public": prompt.is_public,
            "version": str(prompt.version),
            "tags": prompt.tags,
            "model_id": prompt.model_id,
            "cover_img": prompt.cover_img,
            "created_at": prompt.created_at.isoformat() if prompt.created_at else None,
            "updated_at": prompt.updated_at.isoformat() if prompt.updated_at else None,
            "model": model_info
        }
        result.append(prompt_dict)
    
    # 计算总页数
    total_pages = (total + page_size - 1) // page_size
    
    return {
        "items": result,
        "total": total,
        "page": page,
        "page_size": page_size,
        "total_pages": total_pages
    }

# 获取所有提示（保持原有接口兼容性）
@router.get('/', response_model=List[PromptResponse])
def get_prompts(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
    tag: Optional[str] = Query(None),
    title: Optional[str] = Query(None)
):
    query = db.query(Prompt).filter(Prompt.user_id == current_user.id)

    if tag:
        query = query.filter(Prompt.tags.like(f'%{tag}%'))

    if title:
        query = query.filter(Prompt.title == title)

    prompts = query.order_by(Prompt.created_at.desc()).all()
    
    # 手动转换每个提示对象，包含模型信息
    result = []
    for prompt in prompts:
        # 获取模型信息
        model_info = None
        if prompt.model_id:
            model = db.query(ModelConfig).filter(ModelConfig.id == prompt.model_id).first()
            if model:
                model_info = {
                    "id": model.id,
                    "channel": model.channel,
                    "channel_id": model.channel_id,
                    "model": model.model,
                    "temperature": model.temperature,
                    "max_tokens": model.max_tokens,
                    "top_p": model.top_p,
                    "presence_penalty": model.presence_penalty,
                    "frequency_penalty": model.frequency_penalty,
                    "n": model.n,
                    "stop": model.stop,
                    "logit_bias": model.logit_bias,
                    "stream": model.stream,
                    "response_format": model.response_format,
                    "endpoint_url": model.endpoint_url,
                    "file_path": model.file_path,
                    "api_key": model.api_key,
                    "created_at": model.created_at.isoformat() if model.created_at else None,
                    "updated_at": None  # ModelConfig 没有 updated_at 字段
                }
        
        prompt_dict = {
            "id": str(prompt.id),
            "title": prompt.title,
            "content": prompt.content,
            "description": prompt.description,
            "user_id": str(prompt.user_id),
            "is_public": prompt.is_public,
            "version": str(prompt.version),  # 确保是字符串
            "tags": prompt.tags,
            "model_id": prompt.model_id,
            "cover_img": prompt.cover_img,
            "created_at": prompt.created_at.isoformat() if prompt.created_at else None,
            "updated_at": prompt.updated_at.isoformat() if prompt.updated_at else None,
            "model": model_info
        }
        result.append(prompt_dict)
    
    return result

# 检查标题+版本号是否重复
@router.get('/check-duplicate')
def check_duplicate_prompt(
    title: str = Query(..., description="提示词标题"),
    version: str = Query(..., description="版本号"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    检查指定标题和版本号的提示词是否已存在
    """
    existing_prompt = db.query(Prompt).filter(
        Prompt.title == title,
        Prompt.version == version,
        Prompt.user_id == current_user.id
    ).first()
    
    return {
        "exists": existing_prompt is not None,
        "message": "存在标题与版本号相同的提示词，请核查" if existing_prompt else "可以创建"
    }

# 获取单个提示
@router.get('/{prompt_id}', response_model=PromptResponse)
def get_prompt(
    prompt_id: str,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    print("=== 环境变量调试 ===")
    print(f"GET_CHANNEL_URL: {os.getenv('GET_CHANNEL_URL')}")
    print(f"PROMPT_API_USER_KEY: {os.getenv('PROMPT_API_USER_KEY')}")
    print(f"PROMPT_API_AUTHORIZATION: {os.getenv('PROMPT_API_AUTHORIZATION')}")
    print("==================")

    prompt = db.query(Prompt).filter(
        Prompt.id == prompt_id,
        Prompt.user_id == current_user.id
    ).first()
    
    if not prompt:
        raise HTTPException(status_code=404, detail="提示词不存在或无权访问")
    
    # 手动转换提示对象
    return {
        "id": str(prompt.id),
        "title": prompt.title,
        "content": prompt.content,
        "description": prompt.description,
        "user_id": str(prompt.user_id),
        "is_public": prompt.is_public,
        "version": str(prompt.version),
        "tags": prompt.tags,
        "model_id": prompt.model_id,
        "cover_img": prompt.cover_img,
        "created_at": prompt.created_at.isoformat() if prompt.created_at else None,
        "updated_at": prompt.updated_at.isoformat() if prompt.updated_at else None
    }

# 创建新提示
@router.post('/', response_model=PromptResponse)
def create_prompt(
    prompt_data: PromptCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    prompt_id = str(uuid.uuid4())
    new_prompt = Prompt(
        id=prompt_id,
        title=prompt_data.title,
        content=prompt_data.content,
        description=prompt_data.description,
        user_id=current_user.id,
        is_public=True,
        version=prompt_data.version,
        tags=prompt_data.tags,
        model_id=prompt_data.model_id,
        cover_img=prompt_data.cover_img
    )
    db.add(new_prompt)
    db.commit()
    db.refresh(new_prompt)
    
    # 手动转换新创建的提示对象
    return {
        "id": str(new_prompt.id),
        "title": new_prompt.title,
        "content": new_prompt.content,
        "description": new_prompt.description,
        "user_id": str(new_prompt.user_id),
        "is_public": new_prompt.is_public,
        "version": str(new_prompt.version),
        "tags": new_prompt.tags,
        "model_id": new_prompt.model_id,
        "cover_img": new_prompt.cover_img,
        "created_at": new_prompt.created_at.isoformat() if new_prompt.created_at else None,
        "updated_at": new_prompt.updated_at.isoformat() if new_prompt.updated_at else None
    }

# 更新提示
@router.put('/{prompt_id}', response_model=PromptResponse)
def update_prompt(
    prompt_id: str,
    prompt_data: PromptCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    prompt = db.query(Prompt).filter(
        Prompt.id == prompt_id,
        Prompt.user_id == current_user.id
    ).first()
    
    if not prompt:
        raise HTTPException(status_code=404, detail="提示词不存在或无权访问")
    
    # 更新提示信息
    prompt.title = prompt_data.title
    prompt.content = prompt_data.content
    prompt.description = prompt_data.description
    prompt.version = prompt_data.version
    prompt.tags = prompt_data.tags
    prompt.model_id = prompt_data.model_id
    prompt.cover_img = prompt_data.cover_img
    prompt.updated_at = datetime.datetime.now(timezone.utc)
    
    db.commit()
    db.refresh(prompt)
    
    # 手动转换提示对象
    return {
        "id": str(prompt.id),
        "title": prompt.title,
        "content": prompt.content,
        "description": prompt.description,
        "user_id": str(prompt.user_id),
        "is_public": prompt.is_public,
        "version": str(prompt.version),
        "tags": prompt.tags,
        "model_id": prompt.model_id,
        "cover_img": prompt.cover_img,
        "created_at": prompt.created_at.isoformat() if prompt.created_at else None,
        "updated_at": prompt.updated_at.isoformat() if prompt.updated_at else None
    }

# 删除提示词
@router.delete('/deletePrompts')
def delete_prompt_by_title_version(
    title: str = Query(..., description="提示词标题"),
    version: str = Query(..., description="提示词版本"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    # 根据标题和版本号查找提示词
    prompt = db.query(Prompt).filter(
        Prompt.title == title,
        Prompt.version == version,
        Prompt.user_id == current_user.id
    ).first()
    
    if not prompt:
        raise HTTPException(status_code=404, detail="提示词不存在或无权访问")
    
    # 删除提示词
    db.delete(prompt)
    db.commit()
    
    return {"message": "删除成功"}

class ModelCreateInline(BaseModel):
    channel_id: Optional[int] = None
    channel: Optional[str] = None
    model: str
    temperature: Optional[float] = 1.0
    max_tokens: Optional[int] = 2048
    top_p: Optional[float] = 1.0
    presence_penalty: Optional[float] = 0.0
    frequency_penalty: Optional[float] = 0.0
    n: Optional[int] = 1
    stop: Optional[List[str]] = None
    logit_bias: Optional[Dict[str, Any]] = None
    stream: Optional[bool] = False
    response_format: Optional[str] = None
    endpoint_url: Optional[str] = None
    file_path: Optional[str] = None
    api_key: Optional[str] = None

class PromptWithModel(BaseModel):
    prompt: Dict[str, Any]
    model: Optional[ModelCreateInline] = None

@router.post('/createPrompts', response_model=UpdatePromptResponse)
def create_prompt_with_model(
    payload: PromptWithModel = Body(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    try:
        # 1. 数据校验
        validation_errors = validate_prompt_data(payload.prompt, payload.model.dict() if payload.model else None)
        if validation_errors:
            return UpdatePromptResponse(
                success=False,
                code=400,
                message=f"数据校验失败: {', '.join(validation_errors)}"
            )
        
        # 2. 检查标题+版本号是否重复
        existing_prompt = db.query(Prompt).filter(
            Prompt.title == payload.prompt.get('title'),
            Prompt.version == payload.prompt.get('version'),
            Prompt.user_id == current_user.id
        ).first()
        
        if existing_prompt:
            return UpdatePromptResponse(
                success=False,
                code=400,
                message="存在标题与版本号相同的提示词，请核查"
            )
        
        # 3. 开启事务创建模型和提示词
        model_id = None
        if payload.model:
            model_cfg = ModelConfig(**payload.model.dict())
            db.add(model_cfg)
            db.flush()  # 先拿到自增ID
            model_id = model_cfg.id
        
        p = payload.prompt
        prompt_id = str(uuid.uuid4())
        new_prompt = Prompt(
            id=prompt_id,
            title=p.get('title'),
            content=p.get('content'),
            description=p.get('description'),
            user_id=current_user.id,
            is_public=True,
            version=p.get('version'),
            tags=p.get('tags'),
            model_id=model_id if model_id is not None else p.get('model_id'),
            cover_img=p.get('cover_img')
        )
        db.add(new_prompt)
        db.commit()
        db.refresh(new_prompt)
        
        return UpdatePromptResponse(
            success=True,
            code=200,
            message="提示词创建成功",
            model_id=new_prompt.model_id,
            tags=new_prompt.tags,
            title=new_prompt.title
        )
    except Exception as e:
        db.rollback()
        return UpdatePromptResponse(
            success=False,
            code=500,
            message=f"创建失败: {str(e)}"
        )


class ModelUpdateInline(ModelCreateInline):
    id: Optional[int] = None

class PromptWithModelUpdate(BaseModel):
    prompt: Dict[str, Any]
    model: Optional[ModelUpdateInline] = None

@router.post('/updatePromptsById', response_model=UpdatePromptResponse)
def update_prompt_with_model(
    payload: PromptWithModelUpdate = Body(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    # 从payload.prompt中获取prompt_id
    prompt_id = payload.prompt.get('id')
    if not prompt_id:
        return UpdatePromptResponse(
            success=False,
            code=400,
            message="提示词ID是必填参数"
        )
    
    prompt = db.query(Prompt).filter(
        Prompt.id == prompt_id,
        Prompt.user_id == current_user.id
    ).first()
    if not prompt:
        return UpdatePromptResponse(
            success=False,
            code=404,
            message="提示词不存在或无权访问"
        )

    try:
        # 1. 数据校验 - 只校验传入的字段
        prompt_data_to_validate = {}
        model_data_to_validate = {}
        
        # 收集要更新的提示词字段
        for field in ['title', 'content', 'description', 'version', 'tags', 'cover_img']:
            if field in payload.prompt:
                prompt_data_to_validate[field] = payload.prompt[field]
        
        # 收集要更新的模型字段
        if payload.model:
            model_data_to_validate = payload.model.dict(exclude_unset=True)
        
        # 执行校验
        validation_errors = validate_prompt_data(prompt_data_to_validate, model_data_to_validate if model_data_to_validate else None)
        if validation_errors:
            return UpdatePromptResponse(
                success=False,
                code=400,
                message=f"数据校验失败: {', '.join(validation_errors)}"
            )
        
        # 2. 判断是否新版本：如果 payload.prompt.version 与数据库中不同，则走"新增版本"
        incoming_version = payload.prompt.get('version', str(prompt.version))
        is_new_version = str(incoming_version) != str(prompt.version)

        model_id = None
        if payload.model:
            if is_new_version:
                # 新版本时（prompts表insert），总是新增模型
                model_cfg = ModelConfig(**payload.model.dict(exclude={'id'}))
                db.add(model_cfg)
                db.flush()
                model_id = model_cfg.id
            else:
                # 不是新版本时（prompts表update），只能更新现有模型，不能新增
                if prompt.model_id:
                    # 更新当前提示词关联的模型
                    model = db.query(ModelConfig).filter(ModelConfig.id == prompt.model_id).first()
                    if not model:
                        return UpdatePromptResponse(
                            success=False,
                            code=404,
                            message="当前提示词关联的模型不存在"
                        )
                    for k, v in payload.model.dict(exclude_unset=True).items():
                        if k == 'id':
                            continue
                        setattr(model, k, v)
                    db.flush()
                    model_id = model.id
                else:
                    # 如果当前提示词没有关联模型，则新增模型
                    model_cfg = ModelConfig(**payload.model.dict(exclude={'id'}))
                    db.add(model_cfg)
                    db.flush()
                    model_id = model_cfg.id
        else:
            # 没有提供模型数据时，保持原有模型ID
            model_id = prompt.model_id

        if is_new_version:
            # 新增提示词版本
            new_prompt = Prompt(
                id=str(uuid.uuid4()),
                title=payload.prompt.get('title', prompt.title),
                content=payload.prompt.get('content', prompt.content),
                description=payload.prompt.get('description', prompt.description),
                user_id=current_user.id,
                is_public=True,
                version=incoming_version,
                tags=payload.prompt.get('tags', prompt.tags),
                model_id=model_id,
                cover_img=payload.prompt.get('cover_img', prompt.cover_img)
            )
            db.add(new_prompt)
            db.commit()
            db.refresh(new_prompt)
            return UpdatePromptResponse(
                success=True,
                code=200,
                message="提示词版本创建成功",
                model_id=model_id,
                tags=new_prompt.tags,
                title=new_prompt.title
            )
        else:
            # 原地更新 - 只更新传入的字段
            for field, value in payload.prompt.items():
                if hasattr(prompt, field) and field != 'id':
                    setattr(prompt, field, value)
            
            if model_id is not None:
                prompt.model_id = model_id
            
            prompt.updated_at = datetime.datetime.now(timezone.utc)
            db.commit()
            db.refresh(prompt)
            return UpdatePromptResponse(
                success=True,
                code=200,
                message="提示词更新成功",
                model_id=model_id,
                tags=prompt.tags,
                title=prompt.title
            )
    except Exception as e:
        db.rollback()
        return UpdatePromptResponse(
            success=False,
            code=500,
            message=f"更新失败: {str(e)}"
        )

# 根据标题和版本号删除提示词接口
@router.delete('/delete_by_title_version')
def delete_prompt_by_title_version(
    title: str = Query(..., description="提示词标题，必填"),
    version: str = Query(..., description="提示词版本，必填"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    根据标题和版本号删除提示词接口
    入参：提示词标题、提示词版本（必填）
    """
    try:
        # 查找要删除的提示词
        prompt = db.query(Prompt).filter(
            Prompt.title == title,
            Prompt.version == version,
            Prompt.user_id == current_user.id
        ).first()
        
        if not prompt:
            raise HTTPException(
                status_code=404, 
                detail="提示词不存在或无权访问"
            )
        
        # 删除提示词
        db.delete(prompt)
        db.commit()
        
        return {
            "message": "删除成功",
            "deleted_prompt": {
                "id": str(prompt.id),
                "title": prompt.title,
                "version": str(prompt.version)
            }
        }
    except HTTPException:
        db.rollback()
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=400, detail=str(e))